package gitee.derumin.railway_accelerator.mixin;

import gitee.derumin.railway_accelerator.things.FurnaceBehavior;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.recipe.Ingredient;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import static gitee.derumin.railway_accelerator.Railway_accelerator.CONFIG;


@Mixin(FurnaceMinecartEntity.class)
public abstract class FurnaceMinecartEntityMixin extends AbstractMinecartEntity implements FurnaceBehavior {
    @Shadow protected abstract void setLit(boolean lit);

    @Shadow protected abstract boolean isLit();

    @Shadow @Final private static Ingredient ACCEPTABLE_FUEL;
    @Shadow private int fuel;
    @Unique private boolean canMove = true;
    @Unique private double powerOutput = 0.25d;
    @Unique private double power = 0d;

    protected FurnaceMinecartEntityMixin(EntityType<?> entityType, World world) {
        super(entityType, world);
    }

    @Override
    public double railway_accelerator$getPush(){
        return super.railway_accelerator$getPush()
                +((canMove && this.isOnRail() && this.power > 0d)? CONFIG.getMaxPower()*this.powerOutput : 0d);
    }

    @Override
    public double railway_accelerator$getResistance(){
        return super.railway_accelerator$getResistance()
                +(this.powerOutput > 1.0E-7? 0d : this.railway_accelerator$getLineVelocity()*1.414213562373d);
    }

    @Override
    public ConnectionStatus railway_accelerator$follow(AbstractMinecartEntity goal, double delta, boolean firstMove){
        this.canMove = true;
        return super.railway_accelerator$follow(goal, delta, firstMove);
    }

    @Override
    public double railway_accelerator$moveOneStep(double tickRemains, boolean firstMove){
        this.canMove = true;
        return super.railway_accelerator$moveOneStep(tickRemains, firstMove);
    }

    @Override
    public boolean railway_accelerator$canMove(){
        return this.canMove;
    }

    @Override
    public void onActivatorRail(int x, int y, int z, boolean powered) {
        this.canMove = !powered;
    }

    @Inject(method = "tick", at = @At("HEAD"), cancellable = true)
    private void tickRule(CallbackInfo ci){
        super.tick();
        if (!this.getWorld().isClient()) {
            if (this.power > 0d) {
                this.power -= this.canMove? Math.max(this.powerOutput*this.powerOutput, 0.025d) : 0.025d;
                this.fuel = (int)this.power;
                this.setLit(true);
            }else {
                this.fuel = 0;
                this.setLit(false);
            }
        }
        if (this.isLit() && this.random.nextDouble() < this.powerOutput) {
            this.getWorld().addParticle(ParticleTypes.LARGE_SMOKE, this.getX(), this.getY() + 0.8d, this.getZ(), 0.0d, 0.0d, 0.0d);
        }
        ci.cancel();
    }

    @Inject(method = "interact", at = @At("HEAD"), cancellable = true)
    private void interactRule(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir){
        if (!player.shouldCancelInteraction()){
            ItemStack itemStack = player.getStackInHand(hand);
            if (ACCEPTABLE_FUEL.test(itemStack)) {
                this.power += CONFIG.coalCalorificValue;
                if (this.power <= 12000d) {
                    itemStack.decrementUnlessCreative(1, player);
                }else {
                    this.power -= CONFIG.coalCalorificValue;
                }
                player.sendMessage(Text.of("剩余燃料:"+ MathHelper.ceil(this.power)), true);
            }else {
                this.powerOutput += 0.25d;
                if (this.powerOutput > 1.001d){
                    this.powerOutput = 0d;
                    player.sendMessage(Text.of("刹车"), true);
                }else {
                    player.sendMessage(Text.of("出力:" + (int) (this.powerOutput * 100) + "%"), true);
                }
            }
            cir.setReturnValue(ActionResult.success(this.getWorld().isClient));
        }else {
            cir.setReturnValue(super.interact(player, hand));
        }
    }

    @Inject(method = "writeCustomDataToNbt", at = @At("RETURN"))
    private void writeFuel(NbtCompound nbt, CallbackInfo ci){
        nbt.putDouble("Power", this.power);
        nbt.putDouble("PowerOutput", this.powerOutput);
    }

    @Inject(method = "readCustomDataFromNbt", at = @At("RETURN"))
    private void readFuel(NbtCompound nbt, CallbackInfo ci){
        this.power = nbt.getDouble("Power");
        this.powerOutput = nbt.getDouble("PowerOutput");
    }
}
